using Microsoft.Extensions.Logging;
using SumerCoreDevOps.Shared.Enums;
using SumerCoreDevOps.Shared.Models;
using System.Text.Json;
using System.Text.RegularExpressions;
using System.Xml.Linq;

namespace SumerCoreDevOps.ExecuteNodeApi.Services;

/// <summary>
/// 项目类型检测服务
/// </summary>
public class ProjectTypeDetector
{
    private readonly ILogger<ProjectTypeDetector> _logger;

    public ProjectTypeDetector(ILogger<ProjectTypeDetector> logger)
    {
        _logger = logger;
    }

    /// <summary>
    /// 检测项目类型并返回环境需求（包含版本信息）
    /// </summary>
    public EnvironmentRequirement? DetectProjectRequirement(string workingDirectory)
    {
        if (!Directory.Exists(workingDirectory))
        {
            _logger.LogWarning("工作目录不存在: {Directory}", workingDirectory);
            return null;
        }

        _logger.LogInformation("开始检测项目需求: {Directory}", workingDirectory);

        // 检测 .NET 项目
        var dotnetReq = DetectDotNetRequirement(workingDirectory);
        if (dotnetReq != null) return dotnetReq;

        // 检测 Java Maven 项目
        var mavenReq = DetectMavenRequirement(workingDirectory);
        if (mavenReq != null) return mavenReq;

        // 检测 Java Gradle 项目
        var gradleReq = DetectGradleRequirement(workingDirectory);
        if (gradleReq != null) return gradleReq;

        // 检测 Node.js 项目
        var nodeReq = DetectNodeRequirement(workingDirectory);
        if (nodeReq != null) return nodeReq;

        // 检测 Python 项目
        var pythonReq = DetectPythonRequirement(workingDirectory);
        if (pythonReq != null) return pythonReq;

        // 检测 Rust 项目
        var rustReq = DetectRustRequirement(workingDirectory);
        if (rustReq != null) return rustReq;

        // 检测 Go 项目
        var goReq = DetectGoRequirement(workingDirectory);
        if (goReq != null) return goReq;

        _logger.LogWarning("无法识别项目类型");
        return null;
    }

    /// <summary>
    /// 检测项目类型
    /// </summary>
    public ProjectType DetectProjectType(string workingDirectory)
    {
        if (!Directory.Exists(workingDirectory))
        {
            _logger.LogWarning("工作目录不存在: {Directory}", workingDirectory);
            return ProjectType.Unknown;
        }

        _logger.LogInformation("开始检测项目类型: {Directory}", workingDirectory);

        // 检测 .NET 项目 (*.csproj, *.sln, *.fsproj, *.vbproj)
        if (Directory.GetFiles(workingDirectory, "*.csproj", SearchOption.TopDirectoryOnly).Any() ||
            Directory.GetFiles(workingDirectory, "*.sln", SearchOption.TopDirectoryOnly).Any() ||
            Directory.GetFiles(workingDirectory, "*.fsproj", SearchOption.TopDirectoryOnly).Any() ||
            Directory.GetFiles(workingDirectory, "*.vbproj", SearchOption.TopDirectoryOnly).Any())
        {
            _logger.LogInformation("检测到 .NET 项目");
            return ProjectType.DotNet;
        }

        // 检测 Java Maven 项目 (pom.xml)
        if (File.Exists(Path.Combine(workingDirectory, "pom.xml")))
        {
            _logger.LogInformation("检测到 Maven 项目");
            return ProjectType.JavaMaven;
        }

        // 检测 Java Gradle 项目 (build.gradle 或 build.gradle.kts)
        if (File.Exists(Path.Combine(workingDirectory, "build.gradle")) ||
            File.Exists(Path.Combine(workingDirectory, "build.gradle.kts")))
        {
            _logger.LogInformation("检测到 Gradle 项目");
            return ProjectType.JavaGradle;
        }

        // 检测 Node.js 项目 (package.json)
        var packageJsonPath = Path.Combine(workingDirectory, "package.json");
        if (File.Exists(packageJsonPath))
        {
            // 检测锁文件来判断包管理器
            if (File.Exists(Path.Combine(workingDirectory, "pnpm-lock.yaml")))
            {
                _logger.LogInformation("检测到 Node.js (PNPM) 项目");
                return ProjectType.NodeJsPnpm;
            }
            if (File.Exists(Path.Combine(workingDirectory, "yarn.lock")))
            {
                _logger.LogInformation("检测到 Node.js (Yarn) 项目");
                return ProjectType.NodeJsYarn;
            }
            _logger.LogInformation("检测到 Node.js (NPM) 项目");
            return ProjectType.NodeJsNpm;
        }

        // 检测 Python 项目 (setup.py, pyproject.toml, requirements.txt)
        if (File.Exists(Path.Combine(workingDirectory, "setup.py")) ||
            File.Exists(Path.Combine(workingDirectory, "pyproject.toml")) ||
            File.Exists(Path.Combine(workingDirectory, "requirements.txt")))
        {
            _logger.LogInformation("检测到 Python 项目");
            return ProjectType.Python;
        }

        // 检测 Rust 项目 (Cargo.toml)
        if (File.Exists(Path.Combine(workingDirectory, "Cargo.toml")))
        {
            _logger.LogInformation("检测到 Rust 项目");
            return ProjectType.Rust;
        }

        // 检测 Go 项目 (go.mod)
        if (File.Exists(Path.Combine(workingDirectory, "go.mod")))
        {
            _logger.LogInformation("检测到 Go 项目");
            return ProjectType.Go;
        }

        // 检测 PHP 项目 (composer.json)
        if (File.Exists(Path.Combine(workingDirectory, "composer.json")))
        {
            _logger.LogInformation("检测到 PHP (Composer) 项目");
            return ProjectType.PhpComposer;
        }

        // 检测 Ruby 项目 (Gemfile)
        if (File.Exists(Path.Combine(workingDirectory, "Gemfile")))
        {
            _logger.LogInformation("检测到 Ruby 项目");
            return ProjectType.Ruby;
        }

        // 检测 Docker 项目 (Dockerfile)
        if (File.Exists(Path.Combine(workingDirectory, "Dockerfile")))
        {
            _logger.LogInformation("检测到 Docker 项目");
            return ProjectType.Docker;
        }

        _logger.LogWarning("无法识别项目类型");
        return ProjectType.Unknown;
    }

    /// <summary>
    /// 获取默认构建命令
    /// </summary>
    public string GetDefaultBuildCommand(ProjectType projectType)
    {
        return projectType switch
        {
            ProjectType.DotNet => "dotnet build",
            ProjectType.JavaMaven => "mvn clean package",
            ProjectType.JavaGradle => "gradle build",
            ProjectType.NodeJsNpm => "npm run build",
            ProjectType.NodeJsYarn => "yarn build",
            ProjectType.NodeJsPnpm => "pnpm build",
            ProjectType.Python => "python setup.py build",
            ProjectType.Rust => "cargo build --release",
            ProjectType.Go => "go build",
            ProjectType.PhpComposer => "composer install",
            ProjectType.Ruby => "bundle install",
            ProjectType.Docker => "docker build -t app:latest .",
            _ => string.Empty
        };
    }

    /// <summary>
    /// 自动检测并获取构建命令
    /// </summary>
    public string DetectAndGetBuildCommand(string workingDirectory)
    {
        var projectType = DetectProjectType(workingDirectory);
        var command = GetDefaultBuildCommand(projectType);

        if (string.IsNullOrEmpty(command))
        {
            _logger.LogWarning("无法为项目类型 {ProjectType} 生成构建命令", projectType);
        }
        else
        {
            _logger.LogInformation("生成构建命令: {Command} (项目类型: {ProjectType})", command, projectType);
        }

        return command;
    }

    /// <summary>
    /// 获取默认测试命令
    /// </summary>
    public string GetDefaultTestCommand(ProjectType projectType)
    {
        return projectType switch
        {
            ProjectType.DotNet => "dotnet test",
            ProjectType.JavaMaven => "mvn test",
            ProjectType.JavaGradle => "gradle test",
            ProjectType.NodeJsNpm => "npm test",
            ProjectType.NodeJsYarn => "yarn test",
            ProjectType.NodeJsPnpm => "pnpm test",
            ProjectType.Python => "pytest",
            ProjectType.Rust => "cargo test",
            ProjectType.Go => "go test ./...",
            ProjectType.PhpComposer => "phpunit",
            ProjectType.Ruby => "bundle exec rspec",
            _ => string.Empty
        };
    }

    /// <summary>
    /// 自动检测并获取测试命令
    /// </summary>
    public string DetectAndGetTestCommand(string workingDirectory)
    {
        var projectType = DetectProjectType(workingDirectory);
        return GetDefaultTestCommand(projectType);
    }

    #region 版本检测方法

    /// <summary>
    /// 检测 .NET 项目需求（从 .csproj 文件读取 TargetFramework）
    /// </summary>
    private EnvironmentRequirement? DetectDotNetRequirement(string workingDirectory)
    {
        var csprojFiles = Directory.GetFiles(workingDirectory, "*.csproj", SearchOption.TopDirectoryOnly);
        if (!csprojFiles.Any()) return null;

        try
        {
            var csprojPath = csprojFiles.First();
            var doc = XDocument.Load(csprojPath);

            // 读取 TargetFramework，例如：net9.0, net8.0, net6.0
            var targetFramework = doc.Descendants("TargetFramework").FirstOrDefault()?.Value
                ?? doc.Descendants("TargetFrameworks").FirstOrDefault()?.Value?.Split(';').First();

            if (!string.IsNullOrEmpty(targetFramework))
            {
                // 解析版本号：net9.0 -> 9.0, net8.0 -> 8.0
                var match = Regex.Match(targetFramework, @"net(\d+\.\d+)");
                if (match.Success)
                {
                    var version = match.Groups[1].Value;
                    _logger.LogInformation("检测到 .NET 项目，目标框架: {Framework}, 所需版本: {Version}",
                        targetFramework, version);

                    return new EnvironmentRequirement
                    {
                        Name = "dotnet",
                        MinVersion = version,
                        RecommendedVersion = version,
                        IsRequired = true
                    };
                }
            }

            // 如果无法解析版本，返回基本需求
            _logger.LogInformation("检测到 .NET 项目，但无法解析版本");
            return new EnvironmentRequirement { Name = "dotnet", IsRequired = true };
        }
        catch (Exception ex)
        {
            _logger.LogWarning(ex, "解析 .csproj 文件失败");
            return new EnvironmentRequirement { Name = "dotnet", IsRequired = true };
        }
    }

    /// <summary>
    /// 检测 Maven 项目需求（从 pom.xml 读取 Java 版本）
    /// </summary>
    private EnvironmentRequirement? DetectMavenRequirement(string workingDirectory)
    {
        var pomPath = Path.Combine(workingDirectory, "pom.xml");
        if (!File.Exists(pomPath)) return null;

        try
        {
            var doc = XDocument.Load(pomPath);
            var ns = doc.Root?.Name.Namespace;

            // 读取 maven.compiler.source 或 maven.compiler.release
            var properties = ns != null ? doc.Descendants(ns + "properties").FirstOrDefault() : null;
            var javaVersion = properties?.Element(ns! + "maven.compiler.release")?.Value
                ?? properties?.Element(ns! + "maven.compiler.source")?.Value
                ?? properties?.Element(ns! + "java.version")?.Value;

            if (!string.IsNullOrEmpty(javaVersion))
            {
                _logger.LogInformation("检测到 Maven 项目，Java 版本: {Version}", javaVersion);
                return new EnvironmentRequirement
                {
                    Name = "java",
                    MinVersion = javaVersion,
                    RecommendedVersion = javaVersion,
                    IsRequired = true
                };
            }

            _logger.LogInformation("检测到 Maven 项目，但无法解析 Java 版本");
            return new EnvironmentRequirement { Name = "java", IsRequired = true };
        }
        catch (Exception ex)
        {
            _logger.LogWarning(ex, "解析 pom.xml 文件失败");
            return new EnvironmentRequirement { Name = "java", IsRequired = true };
        }
    }

    /// <summary>
    /// 检测 Gradle 项目需求（从 build.gradle 读取 Java 版本）
    /// </summary>
    private EnvironmentRequirement? DetectGradleRequirement(string workingDirectory)
    {
        var buildGradlePath = Path.Combine(workingDirectory, "build.gradle");
        var buildGradleKtsPath = Path.Combine(workingDirectory, "build.gradle.kts");

        string? gradleFile = null;
        if (File.Exists(buildGradlePath)) gradleFile = buildGradlePath;
        else if (File.Exists(buildGradleKtsPath)) gradleFile = buildGradleKtsPath;
        else return null;

        try
        {
            var content = File.ReadAllText(gradleFile);

            // 查找 sourceCompatibility 或 targetCompatibility
            var match = Regex.Match(content, @"(?:sourceCompatibility|targetCompatibility)\s*=\s*['""]?(\d+\.?\d*)['""]?");
            if (match.Success)
            {
                var version = match.Groups[1].Value;
                _logger.LogInformation("检测到 Gradle 项目，Java 版本: {Version}", version);
                return new EnvironmentRequirement
                {
                    Name = "java",
                    MinVersion = version,
                    RecommendedVersion = version,
                    IsRequired = true
                };
            }

            _logger.LogInformation("检测到 Gradle 项目，但无法解析 Java 版本");
            return new EnvironmentRequirement { Name = "java", IsRequired = true };
        }
        catch (Exception ex)
        {
            _logger.LogWarning(ex, "解析 build.gradle 文件失败");
            return new EnvironmentRequirement { Name = "java", IsRequired = true };
        }
    }

    /// <summary>
    /// 检测 Node.js 项目需求（从 package.json 读取 engines）
    /// </summary>
    private EnvironmentRequirement? DetectNodeRequirement(string workingDirectory)
    {
        var packageJsonPath = Path.Combine(workingDirectory, "package.json");
        if (!File.Exists(packageJsonPath)) return null;

        try
        {
            var json = File.ReadAllText(packageJsonPath);
            var doc = JsonDocument.Parse(json);

            // 读取 engines.node
            if (doc.RootElement.TryGetProperty("engines", out var engines))
            {
                if (engines.TryGetProperty("node", out var nodeVersion))
                {
                    var version = nodeVersion.GetString();
                    if (!string.IsNullOrEmpty(version))
                    {
                        // 移除 >= 或 ^ 等符号，提取数字版本
                        var cleanVersion = Regex.Match(version, @"(\d+\.?\d*\.?\d*)").Groups[1].Value;

                        _logger.LogInformation("检测到 Node.js 项目，要求版本: {Version}", cleanVersion);
                        return new EnvironmentRequirement
                        {
                            Name = "node",
                            MinVersion = cleanVersion,
                            RecommendedVersion = cleanVersion,
                            IsRequired = true
                        };
                    }
                }
            }

            _logger.LogInformation("检测到 Node.js 项目，但 package.json 中未指定 engines.node");
            return new EnvironmentRequirement { Name = "node", IsRequired = true };
        }
        catch (Exception ex)
        {
            _logger.LogWarning(ex, "解析 package.json 文件失败");
            return new EnvironmentRequirement { Name = "node", IsRequired = true };
        }
    }

    /// <summary>
    /// 检测 Python 项目需求（从 pyproject.toml 或 setup.py 读取）
    /// </summary>
    private EnvironmentRequirement? DetectPythonRequirement(string workingDirectory)
    {
        // 检查 pyproject.toml
        var pyprojectPath = Path.Combine(workingDirectory, "pyproject.toml");
        if (File.Exists(pyprojectPath))
        {
            try
            {
                var content = File.ReadAllText(pyprojectPath);
                // 查找 requires-python = ">=3.8"
                var match = Regex.Match(content, @"requires-python\s*=\s*['""]>=?(\d+\.\d+)");
                if (match.Success)
                {
                    var version = match.Groups[1].Value;
                    _logger.LogInformation("检测到 Python 项目，要求版本: {Version}", version);
                    return new EnvironmentRequirement
                    {
                        Name = "python",
                        MinVersion = version,
                        RecommendedVersion = version,
                        IsRequired = true
                    };
                }
            }
            catch (Exception ex)
            {
                _logger.LogWarning(ex, "解析 pyproject.toml 文件失败");
            }
        }

        // 检查是否有 Python 相关文件
        if (File.Exists(Path.Combine(workingDirectory, "setup.py")) ||
            File.Exists(Path.Combine(workingDirectory, "requirements.txt")))
        {
            _logger.LogInformation("检测到 Python 项目");
            return new EnvironmentRequirement { Name = "python", IsRequired = true };
        }

        return null;
    }

    /// <summary>
    /// 检测 Rust 项目需求（从 Cargo.toml 读取）
    /// </summary>
    private EnvironmentRequirement? DetectRustRequirement(string workingDirectory)
    {
        var cargoPath = Path.Combine(workingDirectory, "Cargo.toml");
        if (!File.Exists(cargoPath)) return null;

        try
        {
            var content = File.ReadAllText(cargoPath);
            // 查找 rust-version = "1.70"
            var match = Regex.Match(content, @"rust-version\s*=\s*['""](\d+\.\d+)");
            if (match.Success)
            {
                var version = match.Groups[1].Value;
                _logger.LogInformation("检测到 Rust 项目，要求版本: {Version}", version);
                return new EnvironmentRequirement
                {
                    Name = "rust",
                    MinVersion = version,
                    RecommendedVersion = version,
                    IsRequired = true
                };
            }

            _logger.LogInformation("检测到 Rust 项目");
            return new EnvironmentRequirement { Name = "rust", IsRequired = true };
        }
        catch (Exception ex)
        {
            _logger.LogWarning(ex, "解析 Cargo.toml 文件失败");
            return new EnvironmentRequirement { Name = "rust", IsRequired = true };
        }
    }

    /// <summary>
    /// 检测 Go 项目需求（从 go.mod 读取）
    /// </summary>
    private EnvironmentRequirement? DetectGoRequirement(string workingDirectory)
    {
        var goModPath = Path.Combine(workingDirectory, "go.mod");
        if (!File.Exists(goModPath)) return null;

        try
        {
            var content = File.ReadAllText(goModPath);
            // 查找 go 1.21
            var match = Regex.Match(content, @"^go\s+(\d+\.\d+)", RegexOptions.Multiline);
            if (match.Success)
            {
                var version = match.Groups[1].Value;
                _logger.LogInformation("检测到 Go 项目，要求版本: {Version}", version);
                return new EnvironmentRequirement
                {
                    Name = "go",
                    MinVersion = version,
                    RecommendedVersion = version,
                    IsRequired = true
                };
            }

            _logger.LogInformation("检测到 Go 项目");
            return new EnvironmentRequirement { Name = "go", IsRequired = true };
        }
        catch (Exception ex)
        {
            _logger.LogWarning(ex, "解析 go.mod 文件失败");
            return new EnvironmentRequirement { Name = "go", IsRequired = true };
        }
    }

    #endregion
}
